package com.wkbb.basic.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wkbb.basic.config.BasicConfig;
import com.wkbb.basic.enums.DeviceBoxOperateTypeEnum;
import com.wkbb.basic.enums.YouTuOperateTypeEnum;
import com.wkbb.basic.feign.DoorFeignService;
import com.wkbb.basic.mapper.UserMapper;
import com.wkbb.basic.mapper.YoutuFaceMapper;
import com.wkbb.basic.mapper.YoutuPersonMapper;
import com.wkbb.basic.model.*;
import com.wkbb.basic.service.*;
import com.wkbb.basic.thread.DeviceBoxTask;
import com.wkbb.basic.thread.YouTuTask;
import com.wkbb.basic.utils.FileUtil;
import com.wkbb.basic.utils.ImageOfbase64UtilDto;
import com.wkbb.basic.utils.WebankUtil;
import com.wkbb.basic.utils.YouTuUtil;
import com.wkbb.common.base.BaseServiceImpl;
import com.wkbb.common.config.ServiceConfig;
import com.wkbb.common.constants.ErrorCode;
import com.wkbb.common.dto.ResultDTO;
import com.wkbb.common.enums.EntranceEnum;
import com.wkbb.common.enums.FaceTypeEnum;
import com.wkbb.common.redis.RedisTemplateUtil;
import com.wkbb.common.utils.ThreadPoolUtil;
import com.wkbb.common.utils.UuIdUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.net.URL;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author dengjingyuan
 * @date 2020-04-16 20:03
 */
@Service
@Slf4j
public class WebankServiceImpl extends BaseServiceImpl<OrganizationWebank> implements WebankService {

    @Autowired
    private YouTuService youTuService;

    @Autowired
    private RedisTemplateUtil redisTemplateUtil;

    @Autowired
    private ServiceConfig serviceConfig;

    @Autowired
    private OrganizationService organizationService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private YoutuPersonMapper youtuPersonMapper;

    @Autowired
    private YoutuFaceMapper youtuFaceMapper;

    @Autowired
    private DoorFeignService doorFeignService;

    @Autowired
    private DeviceBoxService deviceBoxService;

    @Autowired
    @Lazy
    private XmppService xmppService;

    @Autowired
    private BasicConfig basicConfig;

    @Autowired
    private UserFacePersonConfigService userFacePersonConfigService;

    @Autowired
    private WebankUtilService webankUtilService;

    @Autowired
    private OrganizationWebankService organizationWebankService;

    @Autowired
    private UserOpenService userOpenService;


    @Override
    public ResultDTO<Object> addWeBankUserFace(String picUrlA, String personId, Long orgId, Long accountId, Long userId,Integer type,Short similar) {

        log.info("\n获取用户信息............ 开始..准备开始获取分布式锁......" + youTuService.getAddUserFaceLog(userId, orgId), userId);
        boolean lock = false;
        String result = null;
        int retryCount = 0;
        while (!lock) {
            try {
                lock = redisTemplateUtil.tryLock(youTuService.getAddUserFaceRedisKey(userId, orgId), userId.toString(), 120, TimeUnit.SECONDS);
                log.info("#################" + youTuService.getAddUserFaceLog(userId, orgId), "加锁 ", userId.toString());

            } catch (Exception e) {
                log.error("#################加锁失败..等待锁过期 ：" + youTuService.getAddUserFaceLog(userId, orgId), userId);
                e.printStackTrace();
            }
            if (lock) {//加锁成功

                log.info("--------开始查询学校微众appid--------orgId:{}",orgId);
                OrganizationWebank organizationWebank =organizationWebankService.getOrganizationWebanksByOrgId(orgId,null);
                if(null==organizationWebank){
                    log.info("--------此学校没有绑定微众appid--------orgId:{}",orgId);
                    return null;
                }

                log.info("----------获取当前线程名称----------ThreadName:{}" + youTuService.getAddUserFaceLog(userId, orgId), userId, Thread.currentThread().getName());
                //判断当前用户在当前学校是否有注册人脸,如果没有人脸就注册person并且注册人脸,如果有一张就注册2张,如果有2张就不注册了
                log.info("---------准备注册人脸的学校ID和用户ID----------orgId:{},userId:{}", orgId, userId);
                log.info("---------addUserFace入参---------picUrla:{},userCode:{},orgId:{},accountId:{},userId:{}", picUrlA, personId, orgId, accountId, userId);
                //通过userCode获取个体是否创建
                YoutuPerson youtuPerson = youTuService.getYoutuPerson(orgId, userId);
                try{
                    if (null == youtuPerson) {
                        String newPersonId = createPersonId(userId);
                        //先注册到阅面算法。如果重复注册，会自动检测不处理，人脸有变化会自动更新。
                        ResultDTO<Object> resultDTO = doorFeignService.faceRegist(null,picUrlA,newPersonId,null,UuIdUtil.getGroupIds(serviceConfig.getProfilesActive(), String.valueOf(orgId)));
                        log.info("--------阅面注册成功，开始注册微众--------resultDTO:{}",JSONObject.toJSONString(resultDTO));
                        if(!ResultDTO.checkSuccess(resultDTO)){
                            return resultDTO;
                        }

                        String webankResult =  webankAddUserFace(userId, personId, orgId, picUrlA, organizationWebank, accountId, type, similar,newPersonId);
                        return WebankUtil.returnWebankResult(webankResult);
                    } else {
                        //后台业务重复提交,先删除人脸,再新增人脸
                        //先注册到阅面算法。如果重复注册，会自动检测不处理，人脸有变化会自动更新。
                        ResultDTO<Object> resultDTO = doorFeignService.faceRegist(null,picUrlA,youtuPerson.getPersonId(),null,UuIdUtil.getGroupIds(serviceConfig.getProfilesActive(), String.valueOf(orgId)));
                        log.info("--------阅面注册成功，开始修改微众--------resultDTO:{}",JSONObject.toJSONString(resultDTO));
                        if(!ResultDTO.checkSuccess(resultDTO)){
                            return resultDTO;
                        }
                        result = modifyFace(youtuPerson.getPersonId(), orgId,false,picUrlA, type,  similar);
/*                        if(WebankUtil.checkIfSuccess(result)){
                            result=webankAddUserFace(userId, personId, orgId, imageOfbase64UtilDto_a, organizationWebank, accountId, type, similar);
                        }*/
                    }
                }catch (Exception e){
                    log.error("---------添加人脸失败----------result:{}", result);
                    e.printStackTrace();
                }finally {
                    youTuService.releaseLockAddUserFace(orgId, userId);
                }

                log.info("---------打印人脸注册结果----------result:{}", result);
                try {
                    youTuService.releaseLockAddUserFace(orgId, userId);
                } catch (Exception e) {
                    log.info("#################释放锁失败..等待锁过期 ," + youTuService.getAddUserFaceLog(userId, orgId), userId);
                    e.printStackTrace();
                }
            } else {
                try {
                    retryCount++;
                    if(retryCount>20){
                        log.info("加锁失败，重试超过20次，新增人脸失败...orgId:{}" ,  orgId);
                        break;
                    }
                    log.info("等待500ms重试..." + youTuService.getAddUserFaceLog(userId, orgId), userId);
                    Thread.sleep(500L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return WebankUtil.returnWebankResult(result);
    }


    /**
     *
     * @param personId
     * @param orgId
     * @param flag
     * @param url
     * @return result
     */
    @Override
    public String modifyFace(String personId, Long orgId,Boolean flag,String url,Integer type, Short similar) {

        //查询数据库,如果有人脸,删除以前的人脸,再添加人脸
        Map<String, Object> params = new HashMap<>(1);
        params.put("personId", personId);
        YoutuFace newYouTuFace = youtuFaceMapper.getByMapParams(params);

        String result = null;
        if (null != newYouTuFace) {
            JSONObject jsonObject = new JSONObject();
            log.info("--------开始查询学校微众appid--------orgId:{}", orgId);
            OrganizationWebank organizationWebank = organizationWebankService.getOrganizationWebanksByOrgId(orgId, null);

            if (null == organizationWebank) {
                log.info("--------此学校没有绑定微众appid--------orgId:{}", orgId);
                return null;
            }
            try {
                YoutuPerson youtuPerson = getYoutuPersonByParam(personId);
                if(flag){
                    //在微众删除相应人员
                    result  = webankUtilService.delPerson(personId, false, organizationWebank.getWebankAppid(), organizationWebank.getWebankSecret(), orgId);
                }else{

                    if(null!=youtuPerson){
                        String name = getUserNameByUserId(youtuPerson.getUserId(), personId);
                        log.info("--------开始修改用户人脸信息到微众--------"+youTuService.getAddUserFaceLog(youtuPerson.getUserId(),orgId));
                        //同步人脸信息到微众
                        result = webankUtilService.modifyPerson(youtuPerson.getPersonId(), name, name, "99", "999999", null, url, false,organizationWebank.getWebankAppid(),organizationWebank.getWebankSecret(),orgId);
                    }
                }

                //微众请求成功
                if(JSON.parseObject(result).getString(YouTuUtil.CODE).equals(YouTuUtil.CODE_SUCCESS)&&basicConfig.getUtuFlag()==null?false:basicConfig.getUtuFlag()){
                    //删除优图第一张人脸,并创建个体,附带一张人脸
                    ThreadPoolUtil.addPoolTask(new YouTuTask(YouTuOperateTypeEnum.YOU_TU_OPERATE_DELETE_FACE.getCode().intValue(),youTuService,null,orgId,null,personId,null,null,null,null));
                }
                if(WebankUtil.checkIfSuccess(result)){
                    //如果同步人脸
                    if(flag){
                        youTuService.deleteYouTuFace(personId);
                    }else{
                        youTuService.updateYouTuFace(youtuPerson.getUserId(),orgId, personId,url,type,similar);
                    }

                    //在巨龙盒子删除相应人员
                    ThreadPoolUtil.addPoolTask(new DeviceBoxTask(DeviceBoxOperateTypeEnum.BOX_OPERATE_DELETE_PERSON.getCode().intValue(), deviceBoxService, personId, null,orgId));

                    if (null != youtuPerson) {
                        try {
                            //同步人脸到xmpp
                            userOpenService.xmppUpdatePersonByRole(orgId ,youtuPerson.getUserId());
                        } catch (Exception e) {
                            log.info("----------XMPP请求失败---------,e:{}", e.getMessage());
                        }
                    }
                    log.info("人脸删除成功JsonObject-{}", jsonObject);
                }
            } catch (Exception e) {
                log.info("人脸删除失败JsonObject-{}", e.getMessage());
            }
        }
        return result;
    }

    @Override
    public YoutuPerson getYoutuPersonByParam(String personId) {
        Map<String, Object> params = new HashMap<>(1);
        params.put("personId", personId);
        return youtuPersonMapper.getByMapParams(params);
    }

    @Override
    public Boolean checkPersonId(String personId,Long userId){
        Boolean flag=true;
        try {
            log.info("--------检测新生成的personId是否重复---------,personId:{},userId:{}", personId,userId);
            YoutuPerson newYoutuPerson = getYoutuPersonByParam(personId);
            if(null!=newYoutuPerson){
                return false;
            }
            return true;
        }catch (Exception e){
            log.error("----------检测新生成的personId异常----------",e);
        }
        return true;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addWebankPerson(Long accountId,Long userId,Long orgId,String personId,String url,Integer type,Short similar){
        YoutuPerson youtuPerson = new YoutuPerson();
        youtuPerson.setAccountId(accountId);
        youtuPerson.setUserId(userId);
        youtuPerson.setOrgId(orgId);
        youtuPerson.setPersonId(personId);
        youtuPerson.setStatus(true);
        youtuPersonMapper.insert(youtuPerson);

        YoutuFace youtuFace = new YoutuFace();
        youtuFace.setPersonId(personId);

        youtuFace.setWebUrl(url);
        youtuFace.setFaceType(FaceTypeEnum.JUSTFACE.getValue().byteValue());
        youtuFace.setSourceType(YouTuUtil.SOURCETYPE);
        youtuFace.setWebankStatus(true);
        youtuFaceMapper.insert(youtuFace);

        checkPersonConfig(userId, orgId, type, similar, youtuPerson.getPersonId());
    }

    @Override
    public void checkPersonConfig(Long userId, Long orgId, Integer type, Short similar, String personId) {
        if(null!=type&&type.equals(EntranceEnum.AFTER_SERVER.getValue())){
            //增加或者update配置表new UserFacePersonConfig()
            saveUserFacePersonConfig(userId, orgId, similar, personId);
        }
    }

    @Override
    public void saveUserFacePersonConfig(Long userId, Long orgId, Short similar, String personId) {
        UserFacePersonConfig userFacePersonConfig = new UserFacePersonConfig();
        userFacePersonConfig.setOrgId(orgId);
        userFacePersonConfig.setPersonId(personId);
        userFacePersonConfig.setUserId(userId);
        userFacePersonConfig.setBanFlag(false);
        userFacePersonConfig.setSimilar(similar);
        userFacePersonConfigService.saveConfig(userFacePersonConfig);
    }

//    @Override
//    public Boolean webankCheckResult(String result){
//        if(JSON.parseObject(result).getString(YouTuUtil.CODE).equals(YouTuUtil.CODE_SUCCESS)){
//
//            return true;
//        }
//        return false;
//    }

    private String webankAddUserFace(Long userId,String personId,Long orgId,String picUrlA,OrganizationWebank organizationWebank,Long accountId,Integer type,Short similar,String newPersonId){

        String result = null;

        log.info("----------开始处理微众业务逻辑----------");
        String name = getUserNameByUserId(userId, personId);
        log.info("--------开始同步人脸信息到微众--------{}",youTuService.getAddUserFaceLog(userId,orgId));
        //同步人脸信息到微众
        result = webankUtilService.addPerson(newPersonId, name, name, "99", "999999", null, picUrlA, false,organizationWebank.getWebankAppid(),organizationWebank.getWebankSecret(),orgId);
        log.info("--------同步人脸信息到微众结束--------{},result={}",youTuService.getAddUserFaceLog(userId,orgId),result);

        //成功或用户已存在，直接绑定组
/*        if (WebankUtil.checkIfSuccess(result) || !WebankUtil.userNotExists(result)) {

            if(!webankCheckResult(result)){
                return result;
            }
            log.info("--------开始绑定微众用户和组,绑定失败抛出异常中断人脸注册--------"+youTuService.getAddUserFaceLog(userId,orgId));
            //绑定微众用户和组,绑定失败抛出异常中断人脸注册
            String setWebankGroups = webankUtilService.setGroups(newPersonId, new ArrayList<Object>() {{
                add(orgId);
            }}, false,organizationWebank.getWebankAppid(),organizationWebank.getWebankSecret(),orgId);
            log.info("******微众绑定分组结果******weBankResult:{}", setWebankGroups);
            // 组不存在的情况不处理，以免未同步到微众的学校无法加入人脸
            if (WebankUtil.groupNotExists(setWebankGroups)) {
                if (!WebankUtil.checkIfSuccess(setWebankGroups)) {
                    //微众绑定人脸和组失败
                    log.error("绑定微众人脸到组失败:{}", setWebankGroups);
                    return setWebankGroups;
                }
            }

            log.info("--------绑定微众用户和组,绑定失败抛出异常中断人脸注册结束--------"+youTuService.getAddUserFaceLog(userId,orgId));
        }*/

        //微众请求成功
        if(JSON.parseObject(result).getString(YouTuUtil.CODE).equals(YouTuUtil.CODE_SUCCESS)){

            log.info("----------处理微众业务逻辑结束----------");
            addWebankPerson( accountId, userId, orgId, newPersonId, picUrlA,type,similar);

            if(basicConfig.getUtuFlag()==null?false:basicConfig.getUtuFlag()){
                ImageOfbase64UtilDto imageOfbase64UtilDto = null;
                try{
                    imageOfbase64UtilDto = new ImageOfbase64UtilDto(picUrlA, FileUtil.encodeImageToBase64(new URL(picUrlA)));
                }catch (Exception e){
                    e.printStackTrace();
                }
                //异步创建优图个体
                ThreadPoolUtil.addPoolTask(new YouTuTask(YouTuOperateTypeEnum.YOU_TU_OPERATE_ADD_PERSON.getCode(),youTuService,accountId,orgId,userId,newPersonId,imageOfbase64UtilDto,null,type,similar));
            }

            log.info("----------创建个体结束----------{}", result);
            log.info("--------开始同步人脸信息到巨龙盒子--------" + youTuService.getAddUserFaceLog(userId, orgId));
            //同步人脸信息到巨龙盒子
            ThreadPoolUtil.addPoolTask(new DeviceBoxTask(DeviceBoxOperateTypeEnum.BOX_OPERATE_ADD_PERSON.getCode(), deviceBoxService, newPersonId, picUrlA,orgId));
            log.info("--------同步人脸信息到巨龙盒子结束--------" + youTuService.getAddUserFaceLog(userId, orgId));
            log.info("--------开始同步信息到xmpp--------" + youTuService.getAddUserFaceLog(userId, orgId));
            //获取当前用户身份,同步信息到xmpp
            userOpenService.xmppUpdatePersonByRole(orgId ,userId);
            log.info("--------同步信息到xmpp结束--------" + youTuService.getAddUserFaceLog(userId, orgId));
        }


        //微众注册人员失败的话返回一个不是json的str
        if (!JSON.isValid(result)) {
            youTuService.releaseLockAddUserFace(orgId, userId);
            return result;
        }
        return result;
    }

    @Override
    public String createPersonId(Long userId) {
        //创建个体
        log.info("----------开始创建个体---------}");
        //生成userCode
        String newPersonId = UuIdUtil.getUserCodeByUUId();
        log.info("--------创建个体最新生成的userCode---------,personId:{},userId:{}", newPersonId,userId);

        //创建个体
        log.info("----------开始创建个体---------userId:{}",userId);
        int num=0;

        do {
            //如果personId生产撞了,增加检测机制,最多检测3次
            if(num>0){
                newPersonId = UuIdUtil.getUserCodeByUUId();
            }
            Boolean flag = checkPersonId(newPersonId,userId);
            if(!flag){
                num++;
            }else{
                num=3;
            }
        }while (num<3);
        log.info("--------新生成的personId---------,personId:{}", newPersonId);
        return newPersonId;
    }

    @Override
    public String getUserNameByUserId(Long userId, String personId) {
        String name = personId;
        User user = userMapper.getByPrimaryKey(userId);
        if (user != null) {
            name = user.getName();
        }
        return name;
    }

//    @Override
//    public ResultDTO<Object> returnWebankResult(String result) {
//        if (null == result) {
//            return new ResultDTO<>(ErrorCode.ERRROR_WEBANKAPPID);
//        }else if(WebankUtil.userNotExists(result)){
//            return new ResultDTO<>(ErrorCode.PERSONIDNOTEXIST);
//        }else if(WebankUtil.groupNotExists(result)){
//            return new ResultDTO<>(ErrorCode.ERRROR_NULL_GROUP);
//        }else if(WebankUtil.userNotMyFaceExists(result)){
//            return new ResultDTO<>(ErrorCode.CHECKFACE_2120020);
//        }
//
//        if (!webankCheckResult(result)) {
//            return new ResultDTO<>(ErrorCode.CHECKFACEERROR);
//        }
//
//        return new ResultDTO<>();
//    }
}
